/* 
 * Copyright (c) 2004-2005 Massachusetts Institute of Technology. This code was
 * developed as part of the Haystack (http://haystack.lcs.mit.edu/) research 
 * project at MIT. Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation files (the 
 * "Software"), to deal in the Software without restriction, including without 
 * limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom
 * the Software is furnished to do so, subject to the following conditions: 
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software. 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 */
/*
 * Created on Jun 13, 2004
 *
 */
package edu.mit.csail.relo.eclipse.gef;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.collections.Closure;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;


/**
 * An Incremental Visualization consists of a Model, the current part shown of 
 * the model, the controller, and the view. This requires the currently shown
 * part of the model to be stored - this class provides that support. This 
 * class essentially provides support for managing a copy of the model.
 * 
 * @author vineet
 */
public abstract class IncrementalGraphicalEditPart extends AbstractGraphicalEditPart2 {

    protected List<Object> childrenCU = new ArrayList<Object>();
    protected List<Object> srcRel = new ArrayList<Object>();
    protected List<Object> tgtRel = new ArrayList<Object>();

    @Override
    public List<Object> getModelChildren() {
        return childrenCU;
    }
    public void appendModelChild(Object child) {
        childrenCU.add(child);
    }
    public boolean removeModelChild(Object child) {
        return childrenCU.remove(child);
    }
    public boolean removeModelAndChild(EditPart child) {
        removeChild(child);
        return removeModelChild(child.getModel());
    }
    public void addModelAndChild(EditPart child) {
    	addChild(child);
        appendModelChild(child.getModel());
    }
    public void clearModelChildren() {
        childrenCU.clear();
    }

    @Override
    protected List getModelSourceConnections() {
        return srcRel;
    }

    @Override
    protected List getModelTargetConnections() {
        return tgtRel;
    }
    
	
    // model modification methods (these also modify editpart as well)
    // note: for child adding (as opposed to edit part adding) we support addition
    // based on a  given edit part, since reparenting happens often (can do for connections
    //  but not really needed)
    
    // simple case for not initializing the edit part befre adding the child
    public AbstractGraphicalEditPart appendModelAndChild(Object child) {
        return appendModelAndChild(child, (Closure) null);
    }
    public AbstractGraphicalEditPart appendModelAndChild(Object child, Closure partInitializer) {
        AbstractGraphicalEditPart childAGEP = (AbstractGraphicalEditPart) createChild(child);
        if (childAGEP == null) return null;
        if (partInitializer != null)
            partInitializer.execute(childAGEP);
        return appendModelAndChild(child, childAGEP);
    }
    public AbstractGraphicalEditPart appendModelAndChild(Object child, AbstractGraphicalEditPart childAGEP) {
        if (childAGEP.getParent() != null) { // remove from previous parent
            ((IncrementalGraphicalEditPart) childAGEP.getParent()).removeModelChild(child);
        }
        appendModelChild(child);
        addChild(childAGEP);
        return childAGEP;
    }
    
    /**
     * moves child from old parent to new parent
     * 
     * @param childAGEP - child
     * @param oldIGEP - old parent
     * @param newIGEP - new parent
     */
    public static void moveModelAndChild(
                AbstractGraphicalEditPart childAGEP, 
                IncrementalGraphicalEditPart oldIGEP, 
                IncrementalGraphicalEditPart newIGEP) {
        
    	// maintain childs selection
    	boolean childSel = false;
    	boolean childFoc = false;
    	if (childAGEP.getSelected() != SELECTED_NONE) childSel = true;
    	if (childAGEP.hasFocus()) childFoc = true;

        // append really does the move as well
        newIGEP.appendModelAndChild(childAGEP.getModel(), childAGEP);
        
        //childAGEP.setSelected(sel);
    	if (childSel) childAGEP.getRoot().getViewer().appendSelection(childAGEP);
    	if (childFoc) childAGEP.getRoot().getViewer().setFocus(childAGEP);
    }
    
    public ConnectionEditPart addModelSourceConnections(Object conn) {
        return addModelSourceConnections(conn, null);
    }
    public ConnectionEditPart addModelSourceConnections(Object conn, ConnectionEditPart connEP) {
        if (srcRel.contains(conn)) {
        	System.err.println("ERR: addModelSourceConnections called when relation already exists");
        	(new Exception()).printStackTrace();
        	return findConnection(conn);
        }
    	srcRel.add(conn);
    	if (connEP == null) connEP = createConnection(conn);
        // we don't want to force a refresh model so add the edit part
        addSourceConnection(connEP, getSourceConnections().size());
        return connEP;
    }
    public void removeModelSourceConnections(Object conn) {
        removeModelSourceConnections(conn, null);
    }
    public void removeModelSourceConnections(Object conn, ConnectionEditPart connEP) {
        if (!srcRel.contains(conn)) {
        	System.err.println("ERR: removeModelSourceConnections called when relation does not exist");
        	(new Exception()).printStackTrace();
        	return;
        }
    	if (connEP == null) connEP = findConnection(conn);
        srcRel.remove(conn);
        // we don't want to force a refresh model so add the edit part
        removeSourceConnection(connEP);
    }

    public ConnectionEditPart addModelTargetConnections(Object conn) {
        return addModelTargetConnections(conn, null);
    }
    public ConnectionEditPart addModelTargetConnections(Object conn, ConnectionEditPart connEP) {
        if (tgtRel.contains(conn)) {
        	System.err.println("ERR: addModelTargetConnections called when relation already exists");
        	return findConnection(conn);
        }
    	tgtRel.add(conn);
    	if (connEP == null) connEP = createConnection(conn);
        // we don't want to force a refresh model so add the edit part
        addTargetConnection(connEP, getTargetConnections().size());
        return connEP;
    }
    public void removeModelTargetConnections(Object conn) {
    	removeModelTargetConnections(conn, null);
    }
    public void removeModelTargetConnections(Object conn, ConnectionEditPart connEP) {
        if (!tgtRel.contains(conn)) {
        	System.err.println("ERR: removeModelTargetConnections called when relation does not exist");
        	(new Exception()).printStackTrace();
        	return;
        }
    	if (connEP == null) connEP = findConnection(conn);
        tgtRel.remove(conn);
        // we don't want to force a refresh model so add the edit part
        removeTargetConnection(connEP);
    }

}
